﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace LowLevelGraphics.Filter
{
    /// <summary>
    /// 
    /// </summary>
    /// <param name="r"></param>
    /// <param name="g"></param>
    /// <param name="b"></param>
    /// <returns></returns>
    public delegate byte Threshold2Delegate(byte r, byte g, byte b);

    /// <summary>
    /// Applying threshold to an image
    /// </summary>
    public class Threshold2 : Threshold
    {
        protected byte m_nThreshold = 127;
        protected Threshold2Delegate m_Threshold2Delegate = null;
        /// <summary>
        /// Initializes a new instance of the <see cref="Threshold2"/> class.
        /// </summary>
        public Threshold2()
        {
            m_Threshold2Delegate = new Threshold2Delegate(delegate(byte r, byte b, byte g) { return (byte)((r + b + g) / 3); });
        }

        /// <summary>
        /// Determine threshold
        /// </summary>
        /// <param name="_nThreshold"></param>
        public Threshold2(byte _nThreshold)
            : this()
        {
            m_nThreshold = _nThreshold;
        }

        /// <summary>
        /// used by clone to create a deep copy
        /// </summary>
        /// <param name="_threshold2"></param>
        internal Threshold2(Threshold2 _threshold2)
        {
            this.m_nThreshold = _threshold2.m_nThreshold;
        }

        /// <summary>
        /// Gets or sets threshold function
        /// </summary>
        public Threshold2Delegate ThresholdDelegate
        {
            get { return m_Threshold2Delegate; }
            set { m_Threshold2Delegate = value; }
        }

        /// <summary>
        /// Gets or sets the threshold
        /// </summary>
        public byte Threshold
        {
            get { return m_nThreshold; }
            set { m_nThreshold = value; }
        }

        /// <summary>
        /// Execute thresholding
        /// </summary>
        /// <param name="bmpimg"></param>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            byte nRForeground = m_ColorForeground.R;
            byte nGForeground = m_ColorForeground.G;
            byte nBForeground = m_ColorForeground.B;

            byte nRBackground = m_ColorBackground.R;
            byte nGBackground = m_ColorBackground.G;
            byte nBBackground = m_ColorBackground.B;

            BitmapData data = _bitmap.BitmapData; //bmpimg.LockBits(new Rectangle(0, 0, bmpimg.Width, bmpimg.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            unsafe
            {
                byte* ptr = (byte*)data.Scan0;
                int remain = _bitmap.OffsetPointerIncrease; //data.Stride - data.Width * 4; 

                int nByteCount = _bitmap.BytesPerPixelCount;
                int i = 0;
                int j = 0;
                int nHeight = data.Height;
                int nWidth = data.Width;
                for (i = 0; i < nHeight; i++)
                {
                    for (j = 0; j < nWidth; j++)
                    {
                        ptr[0] = ptr[1] = ptr[2] = (byte)(m_Threshold2Delegate(ptr[0], ptr[1], ptr[2])); //(ptr[0] + ptr[1] + ptr[2]) / 3

                        if (m_nThreshold > ptr[0])
                        {
                            ptr[0] = nBBackground;
                            ptr[1] = nGBackground;
                            ptr[2] = nRBackground;
                        }
                        else
                        {
                            ptr[0] = nBForeground;
                            ptr[1] = nGForeground;
                            ptr[2] = nRForeground;
                        }
                        ptr += nByteCount;
                    }
                    ptr += remain;
                }
            }
            return _bitmap;
        }
        
        /// <summary>
        /// creates a deep copy
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new Threshold2(this);
        }
    }
}
